Allison and Dix proposed an longest common subsequence(LCS) algorithm using bit operations. The idea is based on the observation that each cell [i, j] in the LCS dynamic programing(DP) lattice is either the same as or one more than [i, j-1], so one can record the difference to transform the LCS DP lattice into 0/1. lattice. The time complexity of this algorithm is O(mn/w) time, where w is the word size of the machine.
int AllisonDix_Alg(char *stringA, char *stringB, int m, int n)
{
int i, j, LCS = 0, bitStringCount, neg;
char matchTable[DATATYPE] = { FLASE }, *revStringB;
unsigned char **alphbetString, *stringX, *prevRow, *tempX;
revStringB = (char*) calloc(n + 2, sizeof(char));
revStringB = reverse(stringB, n);
bitStringCount = (int) ceil((double) m / BITSIZE);
// Count the length of bit string
prevRow = (unsigned char*) calloc(bitStringCount + 1, sizeof(unsigned char));
// Init the string X
tempX = (unsigned char*) calloc(bitStringCount + 1, sizeof(unsigned char));
// Init the temp X
stringX = (unsigned char*) calloc(bitStringCount + 1, sizeof(unsigned char));
// Init the string X
for (i = 1; i <= m; i++){
matchTable[stringA[i]] = TRUE;
}
for (i = 1; i <= n; i++){
matchTable[revStringB[i]] = TRUE;
}// Mark the used alphbet
alphbetString = (unsigned char**) calloc(DATATYPE, sizeof(unsigned char*));
// Set the size of alphbet string
for (i = 0; i <= DATATYPE; i++){
if (matchTable[i] == TRUE){
alphbetString[i] = (unsigned char*) calloc(bitStringCount + 1, sizeof(unsigned char));
}
}// Init the size of alphbet string which are used
for (i = 0; i < bitStringCount; i++){
for (j = 1; j <= BITSIZE; j++){
if (m%BITSIZE!=0&&(i == bitStringCount - 1) && (j > m%BITSIZE)){
break;
}
alphbetString[stringA[i*BITSIZE + j]][i + 1] += (int) pow((double) 2, (int) (BITSIZE - j));
}
}// Init the value of alphbet string which are used
for (i = 1; i <= n; i++){
for (j = 1; j <= bitStringCount; j++){
stringX[j] = alphbetString[revStringB[i]][j] | prevRow[j];
}// Process OR operation
for (j = 1; j <= bitStringCount; j++){
prevRow[j] *= 2;
if ((prevRow[j + 1] >= (int) pow((float) 2, (int) BITSIZE - 1)) || (j == bitStringCount)){
prevRow[j] += 1;
}
}// Prev. row left-shift 1 +1
for (j = bitStringCount, neg=0; j >= 1; j--){
if (((stringX[j] - prevRow[j] >= 0) && (neg == 0)) || ((stringX[j] - prevRow[j] - 1 >= 0) && (neg == 1))){
tempX[j] = stringX[j] - prevRow[j];
if (neg == 1){
tempX[j]--;
}
neg = 0;
}
else{
tempX[j] = (int) pow((float) 2, BITSIZE) + stringX[j] - prevRow[j];
if (neg == 1){
tempX[j]--;
}
neg = 1;
}
}// X - Prev. row
for (j = 1; j <= bitStringCount; j++){
tempX[j] ^= stringX[j];
}// Process XOR operation
for (j = 1; j <= bitStringCount; j++){
prevRow[j] = tempX[j] & stringX[j];
}// Process AND operation
}// Main process
for (i = 1; i <= bitStringCount; i++){
for (j = 1; j <= BITSIZE; j++){
if (prevRow[i] % 2 != 0){
LCS++;
}
prevRow[i] /= 2;
}
}// Find the LCS
free(alphbetString);
free(stringX);
free(tempX);
free(prevRow);
free(revStringB);
return LCS;
}